package cn.good.yan.m1;

import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.stereotype.Component;

import java.io.IOException;

/**
 * 监听器 - 监听消息 - 消费者 手动确认ACK
 * 需要启动生产者（MyMessageListener）启动该服务、消费者（Test2）模拟发送消息
 * 生产者发送消息，消费者，这边监听会得到消息
 * 演示 4：消费者监听  -- 没有异常， 默认 消费者接受消息，然后 消费者手动接受消息
 * 演示 5：消费者监听  -- 有异常，  消费者接受消息，出现异常，消费者把消息拒绝，重新放回队列，再次执行，如果再次异常，会被拒绝，不会放回队列
 *
 * @author shengren.yan
 * @create 2024-06-15
 */
@Component
@Slf4j
public class MyACKListener2 {

    public static final String EXCHANGE_DIRECT = "exchange.direct.order";
    public static final String ROUTING_KEY = "order";
    public static final String QUEUE_NAME = "queue.order";

    // 如果 队列、交换机 都已经创建，使用该方法、交换机、绑定关系，直接使用该注解就可以
//    @RabbitListener(queues = {QUEUE_NAME})
    public void processMessage(String dataString, Message message, Channel channel) throws IOException {
        // 注意： 重置消息  需要支持代码的 幂等性
        // 获取当前消息的标识
        long tag = message.getMessageProperties().getDeliveryTag();
        try {
            log.info("消费者 - 接收消息：" + dataString);

            System.out.println(10 / 0);  // 手动制造出异常，让消息回到队列中
            // MQ服务器返回 ACK 确认信息，
            channel.basicAck(tag, false);

        } catch (Exception e) {
            // 获取信息，查看此消息是否曾经被投递过
            Boolean redelivered = message.getMessageProperties().getRedelivered();
            if (!redelivered) {
                // 没有被投递过，那就重新放回队列，重新投递，再试一次
                channel.basicNack(tag, false, true);
            } else {
                // 已经被投递过，且这一次仍然进入了 catch 块，那么返回拒绝此消息，不会回到MQ队列中
                channel.basicReject(tag, false);
                // 该队列的消息，会被拒绝，需要记录日志，人工手动处理

                //  channel.basicNack 与 channel.basicReject 区别
                // basicNack 参数2 ：可以支持批量操作，参数3：是否放回队列
                // basicReject 不支持批量操作，参数2：是否放回队列
            }
        }


    }


    // 修饰监听方法 - 如果队列、交换机 没有创建，使用该方法
//    @RabbitListener(
//            // 设置绑定关系
//            bindings = @QueueBinding(
//                    // 配置队列信息：durable 设置为 true 表示队列持久化；autoDelete 设置为 false 表示关闭自动删除
//                    value = @Queue(value = QUEUE_NAME, durable = "true", autoDelete = "false"),
//                    // 配置交换机信息：durable 设置为 true 表示队列持久化；autoDelete 设置为 false 表示关闭自动删除
//                    exchange = @Exchange(value = EXCHANGE_DIRECT, durable = "true", autoDelete = "false"),
//                    // 配置路由键信息
//                    key = {ROUTING_KEY}
//            ))
//    public void processMessage2(String dataString, Message message, Channel channel) throws IOException {
//         // 注意： 重置消息  需要支持代码的 幂等性
//         // 获取当前消息的标识
//        long tag = message.getMessageProperties().getDeliveryTag();
//        try {
//            log.info("消费者 - 接收消息：" + dataString);
//
//            // System.out.println(10 / 0);  // 手动制造出异常，让消息回到队列中
//            // MQ服务器返回 ACK 确认信息，
//            channel.basicAck(tag, false);
//
//        } catch (Exception e) {
//            // 获取信息，查看此消息是否曾经被投递过
//            Boolean redelivered = message.getMessageProperties().getRedelivered();
//            if (!redelivered) {
//                // 没有被投递过，那就重新放回队列，重新投递，再试一次
//                channel.basicNack(tag, false, true);
//            } else {
//                // 已经被投递过，且这一次仍然进入了 catch 块，那么返回拒绝此消息，不会回到MQ队列中
//                channel.basicReject(tag, false);
//            }
//        }
//    }

}
